package com.evolved.automata.android.bots.speechbot;
import android.widget.*;
import android.content.Context;
import android.util.Log;
import android.view.*;
import android.app.*;
import java.util.*;

public class DataInputPanel extends RelativeLayout {

	
	AutoCompleteTextView newKey;
	AutoCompleteTextView newValue;
	Button addButton;
	Button expandButton;
	DataInputPanel thisDataPanel;
	Hashtable<View, DataRow> buttonToRowMap;
	Hashtable<DataRow, String> rowToKeyNameMap;
	
	Hashtable<String, String> keyValueMap;
	Hashtable<String, String> exportedKeyValueMap;
	Hashtable<String,DataRow> keyDataRowMap;
	InferenceController model;
	
	boolean showDuplicateKeyErrorToastP=false;
	InferenceApp thisContext;
	LinearLayout dataList;
	MacroProcessor macroProcessor;
	
	
	public DataInputPanel(Context context, InferenceController dataModel) {
		super(context);

		model=dataModel;
		thisContext=(InferenceApp)context;
		int dupErrorToast = thisContext.getResources().getInteger(R.integer.show_dupe_key_error_toast);
		showDuplicateKeyErrorToastP = dupErrorToast==1;
		macroProcessor = new MacroProcessor(thisContext);
		/********* Inflate UI **********/
		String infServiceName = Context.LAYOUT_INFLATER_SERVICE;
		LayoutInflater inflater;
		inflater = (LayoutInflater)context.getSystemService(infServiceName);
		inflater.inflate(R.layout.data_panel, this,true);
		
		/********* Define control mappings **********/
		keyValueMap=new Hashtable<String, String>();
		buttonToRowMap = new Hashtable<View, DataRow>();
		keyDataRowMap = new Hashtable<String, DataRow>();
		rowToKeyNameMap = new Hashtable<DataRow, String>();
		thisDataPanel = this;
		exportedKeyValueMap = new Hashtable<String, String>();
		
		/********* Get UI Elements **********/
		addButton=(Button)findViewById(R.id.addPairButton);
		expandButton=(Button)findViewById(R.id.expandedOptionsButton);
		
		newKey = (AutoCompleteTextView)findViewById(R.id.newKey);
		newKey.requestFocus();
		newValue = (AutoCompleteTextView)findViewById(R.id.newValue);
		dataList=(LinearLayout)findViewById(R.id.dataList);
		newKey.setEms(5);
		newValue.setEms(5);
		newKey.setLines(1);
		newValue.setLines(1);
		newKey.setText("");
		newValue.setText("");
		newKey.setHint("[key]");
		newValue.setHint("[value]");
		
		/********* Wire UI Elements **********/
		addButton.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				addDataRowToStructure();
			}
		});
		
//		SetKeyPossibilities(model.getAllKeys());
		newKey.setOnFocusChangeListener(new View.OnFocusChangeListener() {
			
			@Override
			public void onFocusChange(View v, boolean hasFocus) {
				if (hasFocus==true)
				{
					SetKeyPossibilities(model.retrieveAllKeyNames());
				}
				
			}
		});
		
		
		newValue.setOnFocusChangeListener(new View.OnFocusChangeListener() {
			
			@Override
			public void onFocusChange(View v, boolean hasFocus) {
				if (hasFocus==true)
				{
					SetValuePossibilities();
				}
				
			}
		});
		
		
		expandButton.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) 
			{
				
				thisContext.showExpandedDialog(newKey, newValue,false);
				
			}
		});
		
		
	}
		
	
	public void SetKeyPossibilities(String[] keys)
	{
		if (keys!=null)
		{
			ArrayAdapter<String> keyAdapter = new ArrayAdapter<String>(thisContext, R.layout.autocomplete_textview,keys);
			newKey.setAdapter(keyAdapter);
		}
	}
	
	public void SetValuePossibilities()
	{
		String keyName=newKey.getText().toString();
		String[] valuePossibilites = model.retrieveValuesForKey(keyName,20,true);
		String[] help_macros = thisContext.getResources().getStringArray(R.array.macro_help_map);
		
		int baseSize = valuePossibilites.length;
		String[] effectivePossibilities = new String[help_macros.length+baseSize];
		
		for (int i=0;i<baseSize;i++)
		{
			effectivePossibilities[i]=valuePossibilites[i];
		}
		
		for (int i=baseSize;i<baseSize+help_macros.length;i++)
			effectivePossibilities[i]=help_macros[i-baseSize];
		
		if (effectivePossibilities.length>0)
		{
			ArrayAdapter<String> valueAdapter = new ArrayAdapter<String>(thisContext, R.layout.autocomplete_textview,effectivePossibilities);
			newValue.setAdapter(valueAdapter);
		}
	}
	
	
	public Hashtable<String,String> getKeyValuePairs()
	{
		boolean dataConsistent = updateKeyValueMap();
		if (dataConsistent)
			return macroProcessor.transformOutputMap(keyValueMap);
		else
			return null;
	}
	
	public void clearAll()
	{
		for (View button:buttonToRowMap.keySet().toArray(new View[0]))
		{
			RemoveKeyValuePair(button);
		}
	}
	
	
	public void addKeyValuePairsToList(Hashtable<String,String> kvMap)
	{
		
		Set<String> k = kvMap.keySet();
		for (String keyName:k.toArray(new String[0]))
		{
			addKeyValuePairToList(keyName,kvMap.get(keyName));
		}
	}
	
	public void setDataModel(InferenceController dModel)
	{
		model = dModel;
	}
	
	private boolean updateKeyValueMap()
	{
		// TODO: Make this transactional!
		for (DataRow inputPanel:rowToKeyNameMap.keySet().toArray(new DataRow[0]))
		{
			if (!updateKeyValuePair(inputPanel))
				return false;
		}
		return true;
	}
	
	
	
	private void addDataRowToStructure()
	{
		/********* Get the values of key if defined **********/
		
		if ((newKey.getText()!=null)&&(newKey.getText().length()>0))
		{
			String kName=newKey.getText().toString();
			String kValue=newValue.getText().toString();
			
			/********* Check if key name already in map and remove if so**********/
			if (keyValueMap.containsKey(kName))
			{
				RemoveKeyValuePair(kName);
			}
			addKeyValuePairToList(kName,kValue);
			newKey.setText("");
			newValue.setText("");
		}
		
	}
	
	private void addKeyValuePairToList(String keyName, String value)
	{
		if (!keyValueMap.containsKey(keyName))
		{
			DataRow newRow = new DataRow(thisContext,this,"key","value",keyName,value);
			Button removeButton =(Button)newRow.getButton();
			buttonToRowMap.put(removeButton, newRow);
			removeButton.setOnClickListener(getOnClickListener());
			removeButton.setOnLongClickListener(getRemoveButtonLongClickListener());
			keyValueMap.put(keyName, value);
			rowToKeyNameMap.put(newRow, keyName);
			int totalLength=dataList.getChildCount();
			if (value.equals("Question1"))
			{
				dataList.addView(newRow, 0);
			}
			else
			{
				if (keyName.equals("Answer"))
				{
					if (keyValueMap.containsValue("Question1"))
						dataList.addView(newRow, 1);
					else
						dataList.addView(newRow, 0);
				}
				else
					if (keyName.equals("Step"))
					{
						if (keyValueMap.containsKey("Answer"))
						{
							if (keyValueMap.containsValue("Question1"))
							{
								dataList.addView(newRow, 2);
							}
							else
								dataList.addView(newRow, 1);
						}
						else
						{
							if (keyValueMap.containsValue("Question1"))
							{
								dataList.addView(newRow, 1);
							}
							else
								dataList.addView(newRow, 0);
						}
					}
					else
						dataList.addView(newRow, totalLength);
			}

			keyDataRowMap.put(keyName, newRow);
		}
	}
	
	private View.OnClickListener getOnClickListener()
	{
		return new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				RemoveKeyValuePair(v);
			}
		};
	}
	
	private View.OnLongClickListener getRemoveButtonLongClickListener()
	{
		return new View.OnLongClickListener() {
			
			@Override
			public boolean onLongClick(View v) 
			{
				for (View otherViews:buttonToRowMap.keySet().toArray(new View[0]))
				{
					if (otherViews!=v)
					{
						RemoveKeyValuePair(otherViews);
					}
				}
				
				return true;
			}

			
		};
	}
	

	private void RemoveKeyValuePair(View v)
	{
		DataRow pair=buttonToRowMap.get(v);
		dataList.removeView(pair);
		String keyName = rowToKeyNameMap.get(pair);
		keyValueMap.remove(keyName);
		buttonToRowMap.remove(pair.getButton());
		rowToKeyNameMap.remove(pair);
	}
	
	private void RemoveKeyValuePair(String keyName)
	{
		DataRow pair=keyDataRowMap.get(keyName);
		dataList.removeView(pair);
		buttonToRowMap.remove(pair.getButton());
		keyValueMap.remove(keyName);
		keyDataRowMap.remove(keyName);
	}
	
	
	private boolean updateKeyValuePair(DataRow v)
	{
		// Get key/value text
		String keyInput = v.getNameText();
		String valueInput = v.getValueText();
		
		String mappedKeyName = rowToKeyNameMap.get(v);
		String mappedValueName = keyValueMap.get(mappedKeyName);
		
		
		if (keyInput.equals(mappedKeyName)&&valueInput.equals(mappedValueName))
			return true;
		
		if (keyInput.equals(mappedKeyName)&&!valueInput.equals(mappedValueName))
		{
			keyValueMap.put(keyInput, valueInput);
			return true;
		}
		
		if (!keyInput.equals(mappedKeyName))
		{
			if (keyValueMap.containsKey(keyInput))
			{
				if (showDuplicateKeyErrorToastP)
				{
					Toast errorToast = new Toast(thisContext);
					errorToast.setDuration(thisContext.getResources().getInteger(R.integer.error_toast_duration_secs)*1000);
					errorToast.setText(thisContext.getResources().getString(R.string.duplicate_key_error_message));
					errorToast.show();
					
				}
				
			}
			else
			{
				// First, map the key-value that was input to the value that was actually input
				keyValueMap.put(keyInput, valueInput);
				// Remove the old mapped key name
				keyValueMap.remove(mappedKeyName);
				
				// Now map the DataRow View to the correct key name
				rowToKeyNameMap.put(v, keyInput);
				return true;
			}
		}
		
		return false;
		
	}
	
}
